<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        
        <meta name="author" content="隐星魂 (Roy.Sun)">
        
        <link rel="shortcut icon" href="../../img/favicon.ico">
        <title>11.同步 - 玄武操作系统</title>
        <link href="../../css/bootstrap.min.css" rel="stylesheet">
        <link href="../../css/font-awesome.min.css" rel="stylesheet">
        <link href="../../css/base.css" rel="stylesheet">
        <link rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/10.0.3/styles/color-brewer.min.css">

        <script src="../../js/jquery-1.10.2.min.js" defer></script>
        <script src="../../js/bootstrap.min.js" defer></script>
        <script src="https://cdn.staticfile.org/highlight.js/10.0.3/highlight.min.js"></script>
        <script>hljs.initHighlightingOnLoad();</script> 
    </head>

    <body>
        <div class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
            <div class="container">
                <a class="navbar-brand" href="../..">玄武操作系统</a>
                <!-- Expander button -->
                <button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbar-collapse">
                    <span class="navbar-toggler-icon"></span>
                </button>

                <!-- Expanded navigation -->
                <div id="navbar-collapse" class="navbar-collapse collapse">
                        <!-- Main navigation -->
                        <ul class="nav navbar-nav">
                            <li class="navitem">
                                <a href="../.." class="nav-link">主页</a>
                            </li>
                            <li class="navitem">
                                <a href="../../License/" class="nav-link">开源协议</a>
                            </li>
                            <li class="dropdown">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">快速开发指南 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">STM32</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/stm32/01-Envsetup-Guide/" class="dropdown-item">01-开发环境搭建指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/02-atkh743/" class="dropdown-item">02-正点原子阿波罗H743开发板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/03-fk429m/" class="dropdown-item">03-反客F429核心板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/04-atkf103core/" class="dropdown-item">04-正点原子F103核心板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/05-atkf407core/" class="dropdown-item">05-正点原子F407核心板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/06-WeActH750/" class="dropdown-item">06-微行电子H750开发板上手指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/stm32/07-Project-From-Scratch-Guide/" class="dropdown-item">07-自定义工程配置指南</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">GD32</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/gd32/01-Envsetup-Guide/" class="dropdown-item">01-开发环境搭建指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/gd32/02-Project-Setup-Guide/" class="dropdown-item">02-工程配置指南</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">GD32V</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/gd32v/01-Envsetup-Guide/" class="dropdown-item">01-开发环境搭建指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/gd32v/02-Project-Setup-Guide/" class="dropdown-item">02-工程配置指南</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">NXP S32K</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/s32k/01-Envsetup-Guide/" class="dropdown-item">01-开发环境搭建指南</a>
</li>
            
<li>
    <a href="../../QuickGuide/s32k/02-Project-Setup-Guide/" class="dropdown-item">02-工程配置指南</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">玄武内核模块</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../QuickGuide/xwko/01-XuanWuKO-Guide/" class="dropdown-item">01-上手指南</a>
</li>
    </ul>
  </li>
                                </ul>
                            </li>
                            <li class="dropdown active">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">应用手册 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
<li>
    <a href="../00-Index/" class="dropdown-item">0.目录</a>
</li>
                                    
<li>
    <a href="../01-Brief/" class="dropdown-item">1.简介</a>
</li>
                                    
<li>
    <a href="../02-Basic-System-Architecture/" class="dropdown-item">2.系统基本架构</a>
</li>
                                    
<li>
    <a href="../03-Build-System/" class="dropdown-item">3.构建系统</a>
</li>
                                    
<li>
    <a href="../04-Boot-Flow/" class="dropdown-item">4.启动流程</a>
</li>
                                    
<li>
    <a href="../05-IRQ/" class="dropdown-item">5.中断控制</a>
</li>
                                    
<li>
    <a href="../06-SKD/" class="dropdown-item">6.调度器</a>
</li>
                                    
<li>
    <a href="../07-Thread/" class="dropdown-item">7.线程</a>
</li>
                                    
<li>
    <a href="../08-SWT/" class="dropdown-item">8.软件定时器</a>
</li>
                                    
<li>
    <a href="../09-PM/" class="dropdown-item">9.电源管理</a>
</li>
                                    
<li>
    <a href="../10-Lock/" class="dropdown-item">10.锁</a>
</li>
                                    
<li>
    <a href="./" class="dropdown-item active">11.同步</a>
</li>
                                    
<li>
    <a href="../12-MM/" class="dropdown-item">12.内存管理</a>
</li>
                                    
<li>
    <a href="../13-C-Lib/" class="dropdown-item">13.玄武C库</a>
</li>
                                </ul>
                            </li>
                            <li class="dropdown">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">Lua手册 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
<li>
    <a href="../../LuaManual/00-Index/" class="dropdown-item">0.目录</a>
</li>
                                    
<li>
    <a href="../../LuaManual/01-Brief/" class="dropdown-item">1.简介</a>
</li>
                                    
<li>
    <a href="../../LuaManual/02-XWXT/" class="dropdown-item">2.全局导出表</a>
</li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">3.XWOS内核</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../LuaManual/03-XWOS/01-SDK/" class="dropdown-item">3.1.线程库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/02-Spinlock/" class="dropdown-item">3.2.自旋锁库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/03-Seqlock/" class="dropdown-item">3.3.顺序锁库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/04-Mutex/" class="dropdown-item">3.4.互斥锁库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/05-Semaphore/" class="dropdown-item">3.5.信号量库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/06-Condition/" class="dropdown-item">3.6.条件量库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/07-Flag/" class="dropdown-item">3.7.事件标志库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/08-Barrier/" class="dropdown-item">3.8.线程栅栏库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/09-Selector/" class="dropdown-item">3.9.信号选择器库</a>
</li>
            
<li>
    <a href="../../LuaManual/03-XWOS/10-PM/" class="dropdown-item">3.10.电源管理</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">4.玄武Lua函数库</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../LuaManual/04-XWLIB/01-Bitmap/" class="dropdown-item">4.1.位图</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">5.设备栈</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../LuaManual/05-XWDS/01-Soc/" class="dropdown-item">5.1.SOC</a>
</li>
            
<li>
    <a href="../../LuaManual/05-XWDS/02-GPIO/" class="dropdown-item">5.2.GPIO</a>
</li>
            
<li>
    <a href="../../LuaManual/05-XWDS/03-UART/" class="dropdown-item">5.3.UART</a>
</li>
            
<li>
    <a href="../../LuaManual/05-XWDS/04-SPI-Master/" class="dropdown-item">5.4.SPI Master</a>
</li>
            
<li>
    <a href="../../LuaManual/05-XWDS/05-IIC-Master/" class="dropdown-item">5.5.IIC Master</a>
</li>
    </ul>
  </li>
                                </ul>
                            </li>
                            <li class="dropdown">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">移植笔记 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
<li>
    <a href="../../PortingNote/00-Index/" class="dropdown-item">目录</a>
</li>
                                    
<li>
    <a href="../../PortingNote/01-Porting-Note/" class="dropdown-item">移植笔记</a>
</li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">ARM-Cortex-M</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../PortingNote/02-ARM-Cortex-M/01-ARM-Cortex-M-Porting-Note/" class="dropdown-item">架构移植笔记</a>
</li>
            
<li>
    <a href="../../PortingNote/02-ARM-Cortex-M/02-STM32-Porting-Note/" class="dropdown-item">STM32</a>
</li>
    </ul>
  </li>
                                    
  <li class="dropdown-submenu">
    <a href="#" class="dropdown-item">RISC-V</a>
    <ul class="dropdown-menu">
            
<li>
    <a href="../../PortingNote/03-RISC-V/01-GD32V-Porting-Note/" class="dropdown-item">GD32V</a>
</li>
    </ul>
  </li>
                                </ul>
                            </li>
                            <li class="dropdown">
                                <a href="#" class="nav-link dropdown-toggle" data-toggle="dropdown">规范 <b class="caret"></b></a>
                                <ul class="dropdown-menu">
                                    
<li>
    <a href="../../Specification/00-Index/" class="dropdown-item">目录</a>
</li>
                                    
<li>
    <a href="../../Specification/01-Git-Commit-Specification/" class="dropdown-item">git-commit规范</a>
</li>
                                    
<li>
    <a href="../../Specification/02-Version-Branch-Specification/" class="dropdown-item">版本分支规范</a>
</li>
                                </ul>
                            </li>
                        </ul>

                    <ul class="nav navbar-nav ml-auto">
                        <li class="nav-item">
                            <a href="#" class="nav-link" data-toggle="modal" data-target="#mkdocs_search_modal">
                                <i class="fa fa-search"></i> 搜索
                            </a>
                        </li>
                            <li class="nav-item">
                                <a rel="prev" href="../10-Lock/" class="nav-link">
                                    <i class="fa fa-arrow-left"></i> 上一篇
                                </a>
                            </li>
                            <li class="nav-item">
                                <a rel="next" href="../12-MM/" class="nav-link">
                                    下一篇 <i class="fa fa-arrow-right"></i>
                                </a>
                            </li>
                    </ul>
                </div>
            </div>
        </div>

        <div class="container">
            <div class="row">
                    <div class="col-md-3"><div class="navbar-light navbar-expand-md bs-sidebar hidden-print affix" role="complementary">
    <div class="navbar-header">
        <button type="button" class="navbar-toggler collapsed" data-toggle="collapse" data-target="#toc-collapse" title="Table of Contents">
            <span class="fa fa-angle-down"></span>
        </button>
    </div>

    
    <div id="toc-collapse" class="navbar-collapse collapse card bg-secondary">
        <ul class="nav flex-column">
            
            <li class="nav-item" data-level="1"><a href="#_1" class="nav-link">同步</a>
              <ul class="nav flex-column">
            <li class="nav-item" data-level="2"><a href="#_2" class="nav-link">信号量</a>
              <ul class="nav flex-column">
              </ul>
            </li>
            <li class="nav-item" data-level="2"><a href="#_11" class="nav-link">条件量</a>
              <ul class="nav flex-column">
              </ul>
            </li>
            <li class="nav-item" data-level="2"><a href="#_22" class="nav-link">事件标志</a>
              <ul class="nav flex-column">
              </ul>
            </li>
            <li class="nav-item" data-level="2"><a href="#_35" class="nav-link">线程栅栏</a>
              <ul class="nav flex-column">
              </ul>
            </li>
            <li class="nav-item" data-level="2"><a href="#_41" class="nav-link">信号选择器</a>
              <ul class="nav flex-column">
              </ul>
            </li>
              </ul>
            </li>
            
            <li class="nav-item" data-level="1"><a href="#_48" class="nav-link">附录</a>
              <ul class="nav flex-column">
              </ul>
            </li>
        </ul>
    </div>
</div></div>
                    <div class="col-md-9" role="main">

<h1 id="_1">同步</h1>
<p>玄武OS提供多种同步机制，它们统一称为<strong>同步对象</strong>：</p>
<ul>
<li>信号量</li>
<li>条件量</li>
<li>事件标志</li>
<li>线程栅栏</li>
<li>信号选择器</li>
</ul>
<p><strong>信号量</strong>与<strong>条件量</strong>是操作系统最基本的两种同步机制，
其他复杂的同步机制都可基于这两种同步机制实现。</p>
<hr />
<h2 id="_2">信号量</h2>
<h3 id="_3">描述</h3>
<p>信号量通常用于不同代码上下文间的同步，使用PV原语进行操作，
属于操作系统比较底层的同步机制。玄武OS内核的信号量有两种：</p>
<ul>
<li>
<p>管道信号量(PLSEM)：
    对所有阻塞在其等待队列中的线程按照先进先出(FIFO)的策略调度，
    即当信号量可用时，最先进入等待队列中的线程将优先获得信号量。</p>
</li>
<li>
<p>实时信号量(RTSEM)：
    对所有阻塞在其等待队列中的线程按照优先级进行调度，即高优先级
    的线程总是最先获得信号量，同优先级的线程按先进先出(FIFO)的策略调度。</p>
</li>
</ul>
<p>操作系统抽象层的API只封装了一种信号量，当系统配置文件中同时
配置了<code>XWUPCFG_SYNC_PLSEM</code>与<code>XWUPCFG_SYNC_RTSEM</code>时，优先使用实时信号量。</p>
<h3 id="_4">用法</h3>
<h4 id="_5">信号量的创建、初始化与删除、销毁</h4>
<p>信号量支持静态初始化与销毁，动态创建与删除两种方式：</p>
<ul>
<li>
<p>静态初始化与销毁</p>
<ul>
<li><strong>静态</strong>是指用户预先定义对象，这些对象在编译时由编译器分配内存。</li>
<li>初始化：<code>xwos_sem_init()</code></li>
<li>销毁：<code>xwos_sem_destroy()</code></li>
</ul>
</li>
<li>
<p>动态创建与删除</p>
<ul>
<li><strong>动态</strong>是指程序在运行时，通过内存分配函数从某个内存区域上申请分配一块内存，
    并把这块内存初始化为所需要的对象。使用完毕后，需要释放内存。</li>
<li>创建：<code>xwos_sem_create()</code></li>
<li>删除：<code>xwos_sem_delete()</code></li>
</ul>
</li>
</ul>
<h4 id="p">信号量的P操作</h4>
<p>P操作是指发布信号量，使得信号量的计数器加1，同时会唤醒信号量等待队列中的一个线程。
被唤醒的线程会进行V操作，取走信号量中的一个信号，使得信号量的计数器减1。</p>
<ul>
<li>API：<code>xwos_sem_post()</code><ul>
<li>可在中断上下文、中断底半部、线程上下文中使用</li>
</ul>
</li>
</ul>
<h4 id="v">信号量的V操作</h4>
<p>V操作是指取走信号量中的一个信号，使得信号量的计数器减1。</p>
<ul>
<li>API<ul>
<li><code>xwos_sem_trywait()</code><ul>
<li>此API不会等待，只是测试一下信号量，如果失败，就返回<code>-ENODATA</code>；</li>
<li>可在中断上下文、中断底半部、线程上下文中使用；</li>
</ul>
</li>
<li><code>xwos_sem_wait()</code><ul>
<li>只可在线程上下文中使用；</li>
<li>调用的线程若无法获取信号量，将进入<strong>阻塞</strong>状态；</li>
<li>此API可被中断，中断将返回<code>-EINTR</code>；</li>
</ul>
</li>
<li><code>xwos_sem_timedwait()</code><ul>
<li>只可在线程上下文中使用；</li>
<li>调用的线程若无法获取信号量，将进入“<strong>阻塞</strong>”和“<strong>睡眠</strong>”状态；</li>
<li>此API可限时等待信号量，超时将以<code>-ETIMEDOUT</code>返回；</li>
<li>此API可被中断，中断将返回<code>-EINTR</code>；</li>
</ul>
</li>
<li><code>xwos_sem_wait_unintr()</code><ul>
<li>只可在线程上下文中使用；</li>
<li>调用的线程若无法获取信号量，将进入<strong>阻塞</strong>状态；</li>
<li>此API不会被中断，有可能会妨碍系统休眠，需谨慎使用。</li>
</ul>
</li>
</ul>
</li>
</ul>
<h4 id="_6">信号量的中断操作</h4>
<p>中断操作是指玄武OS在处理内核事件时中断线程的<strong>“阻塞”</strong>或<strong>“睡眠”</strong>，
强制使其进入<strong>就绪</strong>状态。<code>xwos_sem_wait()</code>和<code>xwos_sem_timedwait()</code>
会返回<code>-EINTR</code>，但<code>xwos_sem_wait_unintr()</code>不能被中断。相关的内核事件：</p>
<ul>
<li>系统休眠时要求线程冻结</li>
<li>线程从一个CPU迁移到另一个CPU时要求线程冻结</li>
</ul>
<h4 id="_7">信号量的冻结与解冻操作</h4>
<p>被冻结的信号量不允许被发布，但可以被测试。
使用API<code>xwos_sem_wait()</code>、<code>xwos_sem_timedwait()</code>与<code>xwos_sem_wait_unintr()</code>
测试已冻结信号量的线程都将被阻塞。
解冻后，信号量的计数器重新从0开始计数，并可以进行发布操作。</p>
<ul>
<li>冻结API：<code>xwos_sem_freeze()</code></li>
<li>解冻API：<code>xwos_sem_thaw()</code></li>
</ul>
<h4 id="_8">绑定与解绑选择器</h4>
<p>可以将信号量绑定到一个特定的<strong>信号选择器</strong>上。当对信号量进行V操作时，
可向信号选择器发送一个<strong>选择信号</strong>。</p>
<ul>
<li>绑定API：<code>xwos_sem_bind()</code></li>
<li>解绑API：<code>xwos_sem_unbind()</code></li>
</ul>
<p>可以参考<a href="#SYNC-SEL">信号选择器</a>的章节获取更多的信息。</p>
<h3 id="_9">示例</h3>
<ul>
<li>应用模块：<code>xwam/example/sync/sem</code></li>
<li>用法：<ul>
<li>在配置文件<code>xwbd/电路板名称/cfg/xwam.h</code>中
    定义宏<code>XWAMCFG_example_sync_sem</code>为<code>1</code>；</li>
<li>在初始化流程中（例如：<code>xwos_main()</code>）调用<code>example_sem_start()</code>启动模块。</li>
</ul>
</li>
</ul>
<h3 id="_10">配置</h3>
<h5 id="cfgxwosh">cfg/xwos.h</h5>
<ul>
<li>MP内核配置：<ul>
<li>同步<ul>
<li><code>XWMPCFG_SYNC_PLSEM</code>：是否启用管道信号量，取值：1|0；</li>
<li><code>XWMPCFG_SYNC_RTSEM</code>：是否启用实时信号量，取值：1|0；</li>
<li><code>XWMPCFG_SYNC_SEM_MEMSLICE</code>：是否启用信号量对象缓存，取值：1|0；</li>
</ul>
</li>
</ul>
</li>
<li>UP内核配置：<ul>
<li>同步<ul>
<li><code>XWUPCFG_SYNC_PLSEM</code>：是否启用管道信号量，取值：1|0；</li>
<li><code>XWUPCFG_SYNC_RTSEM</code>：是否启用实时信号量，取值：1|0；</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="api">API参考</h3>
<ul>
<li>头文件：<code>xwos/osal/sync/sem.h</code></li>
<li>注释：见头文件</li>
</ul>
<hr />
<h2 id="_11">条件量</h2>
<h3 id="_12">描述</h3>
<p>玄武OS内核提供的条件量与大部分系统/语言提供的条件量功能类似，例如：</p>
<ul>
<li>POSIX的<code>pthread_cond_t</code></li>
<li>C++的<code>std::condition_variable</code></li>
<li>Java的<code>java.util.concurrent.locks.Condition</code></li>
<li>Python的<code>threading.Condition</code></li>
</ul>
<p>条件量常用于多个线程间传递数据。玄武OS内核的条件量还可以用于中断与线程间传递数据。
主要包括两个动作：</p>
<ul>
<li>线程A等待条件量的<strong>条件</strong>成立而阻塞；</li>
<li>另一个线程B或中断使<strong>条件</strong>成立。为了防止两个上下文竞争<strong>条件</strong>，
    条件量需要和一个<strong>锁</strong>一起使用，锁用于保护<strong>条件</strong>不被同时访问。
    玄武OS的条件量支持很多种类型的锁：<ul>
<li>互斥锁</li>
<li>自旋锁</li>
<li>顺序锁</li>
<li>自定义的加锁与解锁函数</li>
</ul>
</li>
</ul>
<h3 id="_13">用法</h3>
<h4 id="_14">条件量的创建、初始化与删除、销毁</h4>
<p>条件量支持静态初始化与销毁，动态创建与删除两种方式：</p>
<ul>
<li>
<p>静态初始化与销毁</p>
<ul>
<li><strong>静态</strong>是指用户预先定义对象，这些对象在编译时由编译器分配内存。</li>
<li>初始化：<code>xwos_cond_init()</code></li>
<li>销毁：<code>xwos_cond_destroy()</code></li>
</ul>
</li>
<li>
<p>动态创建与删除</p>
<ul>
<li><strong>动态</strong>是指程序在运行时，通过内存分配函数从某个内存区域上申请分配一块内存，
    并把这块内存初始化为所需要的对象。使用完毕后，需要释放内存。</li>
<li>创建：<code>xwos_cond_create()</code></li>
<li>删除：<code>xwos_cond_delete()</code></li>
</ul>
</li>
</ul>
<h4 id="_15">等待条件量</h4>
<pre><code class="C">xwer_t xwos_cond_wait(struct xwos_cond * condid,
                      union xwlk_ulock lock, xwsq_t lktype,
                      void * lkdata, xwsq_t * lkst);

xwer_t xwos_cond_timedwait(struct xwos_cond * condid,
                           union xwlk_ulock lock, xwsq_t lktype,
                           void * lkdata, xwtm_t * xwtm, xwsq_t * lkst);
</code></pre>

<ul>
<li>所有锁统一使用<code>union xwlk_ulock</code>指代，此联合中包含所有锁的定义，
    实际只是一个指针，具体意义由<code>xwsq_t lktype</code>决定：<ul>
<li><code>XWOS_LK_MTX</code> 互斥锁<ul>
<li><code>lock</code>代表互斥锁（访问方式：<code>lock.osal.mtx</code>），</li>
<li><code>lockdata</code>无作用，设置为<code>NULL</code>即可；</li>
</ul>
</li>
<li><code>XWOS_LK_MTX_UNINTR</code> 不可中断的互斥锁<ul>
<li><code>lock</code>代表互斥锁（访问方式：<code>lock.osal.mtx</code>），</li>
<li><code>lockdata</code>无作用，设置为<code>NULL</code>即可；</li>
</ul>
</li>
<li><code>XWOS_LK_SPLK</code> 自旋锁<ul>
<li><code>lock</code>代表自旋锁的指针（访问方式：<code>lock.osal.splk</code>）；</li>
<li><code>lockdata</code>无作用，设置为<code>NULL</code>即可；</li>
</ul>
</li>
<li><code>XWOS_LK_SQLK_WR</code> 顺序写锁<ul>
<li><code>lock</code>代表顺序锁的指针（访问方式：<code>lock.osal.sqlk</code>）；</li>
<li><code>lockdata</code>无作用，设置为<code>NULL</code>即可；</li>
</ul>
</li>
<li><code>XWOS_LK_SQLK_RDEX</code> 顺序读锁<ul>
<li><code>lock</code>代表顺序锁的指针（访问方式：<code>lock.osal.sqlk</code>）；</li>
<li><code>lockdata</code>无作用，设置为<code>NULL</code>即可；</li>
</ul>
</li>
<li><code>XWOS_LK_CALLBACK</code> 自定义的加锁与解锁函数<ul>
<li><code>lock</code>代表指向<code>struct xwlk_cblk</code>的指针（访问方式：<code>lock.cb</code>）；</li>
<li><code>lockdata</code>传递给<code>struct xwlk_cblk</code>中的<code>lock</code>与<code>unlock</code>函数的参数；</li>
</ul>
</li>
</ul>
</li>
<li>超时的参数<code>xwtm_t * xwtm</code>用法可以参考<a href="../06-SKD/#SKD-TM">超时管理</a>；</li>
<li><code>lkst</code>指向输出缓冲区，此缓冲区可返回锁的状态：<ul>
<li><code>XWOS_LKST_LOCKED</code>函数返回时，已经上锁；</li>
<li><code>XWOS_LKST_UNLOCKED</code>函数返回时，未上锁。</li>
</ul>
</li>
</ul>
<pre><code>!!!特别注意!!!

-   当使用了带中断管理的上锁函数时，例如：
    -   **xwos_splk_lock_cpuirq()**
    -   **xwos_splk_lock_cpuirqsv()**
    -   **xwos_splk_lock_irqs()**
    -   **xwos_sqlk_wr_lock_cpuirq()**
    -   **xwos_sqlk_wr_lock_cpuirqsv()**
    -   **xwos_sqlk_wr_lock_irqs()**
    -   **xwos_sqlk_rdex_lock_cpuirq()**
    -   **xwos_sqlk_rdex_lock_cpuirqsv()**
    -   **xwos_sqlk_rdex_lock_irqs()**

    **xwos_cond_timedwait()**或**xwos_cond_wait()**返回时需要由用户恢复中断，
    条件量不会管理中断，但可在关闭中断时使用。

-   玄武OS内核的条件量与**pthread_cond_t**不同：
    -   返回值为**XWOK**时才会对锁进行上锁，如果返回小于0的错误码，
        不会上锁；
    -   是否上锁的状态由**lkst**指向的缓冲区返回；
    -   **pthread_cond_wait()**无论如何都会等待互斥锁被上锁时才返回。
</code></pre>

<h4 id="_16">单播条件量</h4>
<p><strong>单播</strong>是指唤醒条件量队列中的第一个线程，条件量队列是一个先进先出（FIFO）队列：</p>
<ul>
<li>API：<code>xwos_cond_unicast()</code>；<ul>
<li>此API可在中断上下文、中断底半部、线程上下文中使用；</li>
</ul>
</li>
<li>若条件量绑定了信号选择器，单播<strong>不</strong>会向信号选择器发送<strong>选择信号</strong>。</li>
</ul>
<h4 id="_17">广播条件量</h4>
<p><strong>广播</strong>是指唤醒条件量队列中的所有线程：</p>
<ul>
<li>API：<code>xwos_cond_broadcast()</code>；<ul>
<li>此API可在中断上下文、中断底半部、线程上下文中使用；</li>
</ul>
</li>
<li>若条件量绑定了信号选择器，广播会向信号选择器发送<strong>选择信号</strong>。</li>
</ul>
<h4 id="_18">条件量的冻结与解冻操作</h4>
<p>被冻结的条件量不允许单播与广播，但可以被等待。</p>
<ul>
<li>冻结API：<code>xwos_cond_freeze()</code></li>
<li>解冻API：<code>xwos_cond_thaw()</code></li>
</ul>
<h4 id="_19">绑定选择器</h4>
<p>可以将条件量绑定到一个特定的信号选择器上。当广播条件量时，可向信号选择器发送<strong>选择信号</strong>。</p>
<ul>
<li>绑定API：<code>xwos_cond_bind()</code></li>
<li>解绑API：<code>xwos_cond_unbind()</code></li>
</ul>
<p>可以参考<a href="#SYNC-SEL">信号选择器</a>的章节获取更多的信息。</p>
<h3 id="_20">示例</h3>
<ul>
<li>应用模块：<code>xwam/example/sync/cond</code></li>
<li>用法：<ul>
<li>在配置文件<code>xwbd/电路板名称/cfg/xwam.h</code>中
    定义宏<code>XWAMCFG_example_sync_cond</code>为<code>1</code>；</li>
<li>在初始化流程中（例如：<code>xwos_main()</code>）调用<code>example_cond_start()</code>启动模块。</li>
</ul>
</li>
</ul>
<h3 id="_21">配置</h3>
<h5 id="cfgxwosh_1">cfg/xwos.h</h5>
<ul>
<li>MP内核配置：<ul>
<li>同步<ul>
<li><code>XWMPCFG_SYNC_COND_MEMSLICE</code>：是否启用条件量对象缓存，取值：1|0；</li>
</ul>
</li>
</ul>
</li>
<li>UP内核配置：<ul>
<li>同步<ul>
<li><code>XWUPCFG_SYNC_COND</code>：是否启用条件量，取值：1|0；</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="api_1">API参考</h3>
<ul>
<li>头文件：<code>xwos/osal/sync/condition.h</code></li>
<li>注释：见头文件</li>
</ul>
<hr />
<h2 id="_22">事件标志</h2>
<h3 id="_23">描述</h3>
<p>当系统需要处理很多事件，如果每个事件都绑定一个特定的条件量，
每个条件量又由一个线程进行等待处理，会导致系统需要大量内存来创建条件量和线程，
这种方法在小内存的MCU上显然不可行。条件量属于操作系统比较底层的功能，
用法虽然灵活但很复杂。因此，玄武OS基于条件量实现了事件标志的功能。</p>
<p>事件标志使用位图来管理一组事件，位图中的每个位代表一个事件，
当一个或多个事件状态发生变化时，事件对应的位也会发生变化，并唤醒正在等待的线程。
线程唤醒后，就可从事件位图中获取事件的状态。</p>
<p>玄武OS的事件标志：</p>
<ul>
<li>线程可以等待位图中的事件位被置1，也可以等待事件位被清0；</li>
<li>线程可以等待位图中的事件位同时被置1（事件与事件之间是逻辑<strong>与</strong>的关系），
    也可以等待其中任意一个位被置1（事件与事件之间是逻辑<strong>或</strong>的关系）；</li>
<li>线程可以等待位图中的事件位同时被清0（事件与事件之间是逻辑<strong>与</strong>的关系），
    也可以等待其中任意一个位被清0（事件与事件之间是逻辑<strong>或</strong>的关系）；</li>
<li>线程可以选择是否<strong>消费</strong>事件，<strong>“消费”</strong>事件是指，当线程等到事件被
    唤醒，可以选择是否<strong>清除</strong>事件标志。<strong>清除</strong>的含义是：<ul>
<li>当线程等待的是位图中的事件位被置1，<strong>清除</strong>是指将这些位清0；</li>
<li>当线程等待的是位图中的事件位被清0，<strong>清除</strong>是指将这些位置1；</li>
</ul>
</li>
<li>线程可以等待事件标志位发生<strong>翻转</strong>，<strong>翻转</strong>是指事件标志位由1变为0，或
    由0变为1，当线程等待的是标志位发生<strong>翻转</strong>，不可<strong>清除</strong>事件标志；</li>
<li>事件位图中的位的最大数量在运行时是固定不变的，但可在编译时进行配置：<ul>
<li>多核系统：<code>XWMPCFG_SYNC_EVT_MAXNUM</code></li>
<li>单核系统：<code>XWUPCFG_SYNC_EVT_MAXNUM</code></li>
</ul>
</li>
</ul>
<h3 id="_24">用法</h3>
<h4 id="_25">事件标志的创建、初始化与删除、销毁</h4>
<p>事件标志支持静态初始化与销毁，动态创建与删除两种方式：</p>
<ul>
<li>
<p>静态初始化与销毁</p>
<ul>
<li><strong>静态</strong>是指用户预先定义对象，这些对象在编译时由编译器分配内存。</li>
<li>初始化：<code>xwos_flg_init()</code></li>
<li>销毁：<code>xwos_flg_destroy()</code></li>
</ul>
</li>
<li>
<p>动态创建与删除</p>
<ul>
<li><strong>动态</strong>是指程序在运行时，通过内存分配函数从某个内存区域上申请分配一块内存，
    并把这块内存初始化为所需要的对象。使用完毕后，需要释放内存。</li>
<li>创建：<code>xwos_flg_create()</code></li>
<li>删除：<code>xwos_flg_delete()</code></li>
</ul>
</li>
</ul>
<h4 id="_26">等待事件</h4>
<p>玄武OS提供3个API产生触发事件：</p>
<ul>
<li><code>xwos_flg_trywait()</code>: 尝试等一下事件标志的触发事件<ul>
<li>可在中断上下文、中断底半部、线程上下文中使用；</li>
</ul>
</li>
<li><code>xwos_flg_wait()</code>: 等待事件标志的触发事件<ul>
<li>只可线程上下文中使用；</li>
</ul>
</li>
<li><code>xwos_flg_timedwait()</code>: 限时等待事件标志的触发事件<ul>
<li>只可线程上下文中使用。</li>
</ul>
</li>
</ul>
<h5 id="_27">触发条件</h5>
<p>当调用等待事件的API时，需要指定一个触发条件（参数：trigger）。
触发条件分为<strong>电平触发</strong>和<strong>边沿触发</strong>。</p>
<h5 id="_28">电平触发</h5>
<p><strong>电平触发</strong>的概念来源于数字电路中，是一种类比，是指事件特定的状态（1或0）
产生唤醒信号，下面的触发条件为电平触发：</p>
<ul>
<li><code>XWOS_FLG_TRIGGER_SET_ALL</code> 所有事件位被置1</li>
<li><code>XWOS_FLG_TRIGGER_SET_ANY</code> 任意事件位被置1</li>
<li><code>XWOS_FLG_TRIGGER_CLR_ALL</code> 所有事件位被清0</li>
<li><code>XWOS_FLG_TRIGGER_CLR_ANY</code> 任意事件位被清0</li>
</ul>
<h5 id="_29">边沿触发</h5>
<p><strong>边沿触发</strong>的概念来源于数字电路中，是一种类比，是指事件状态发生改变
（1变0或0变1）时产生的唤醒信号，下面的触发条件为边沿触发：</p>
<ul>
<li><code>XWOS_FLG_TRIGGER_TGL_ALL</code> 所有事件位发生翻转</li>
<li><code>XWOS_FLG_TRIGGER_TGL_ANY</code> 任意事件位发生翻转</li>
</ul>
<h5 id="_30">清除触发事件</h5>
<ul>
<li>当采用<strong>电平触发</strong>时，需要在触发后清除事件标志位，防止事件重复触发，可以
    在调用等待事件的API指定参数action为<code>XWOS_FLG_ACTION_CONSUMPTION</code>。</li>
<li>当采用<strong>边沿触发</strong>时，不需要清除事件标志位。</li>
</ul>
<h4 id="_31">产生触发事件</h4>
<p>玄武OS提供6个API产生触发事件：</p>
<ul>
<li><code>xwos_flg_s1m()</code>: 同时设置多个事件标志位<ul>
<li>可在中断上下文、中断底半部、线程上下文中使用；</li>
</ul>
</li>
<li><code>xwos_flg_s1i()</code>: 设置单个事件标志位<ul>
<li>可在中断上下文、中断底半部、线程上下文中使用；</li>
</ul>
</li>
<li><code>xwos_flg_c0m()</code>: 同时清除多个事件标志位<ul>
<li>可在中断上下文、中断底半部、线程上下文中使用；</li>
</ul>
</li>
<li><code>xwos_flg_c0i()</code>: 清除单个事件标志位<ul>
<li>可在中断上下文、中断底半部、线程上下文中使用；</li>
</ul>
</li>
<li><code>xwos_flg_x1m()</code>: 同时翻转多个事件标志位<ul>
<li>可在中断上下文、中断底半部、线程上下文中使用；</li>
</ul>
</li>
<li><code>xwos_flg_x1i()</code>: 翻转单个事件标志位<ul>
<li>可在中断上下文、中断底半部、线程上下文中使用。</li>
</ul>
</li>
</ul>
<h4 id="_32">绑定选择器</h4>
<p>可以将事件标志绑定到一个特定的信号选择器上，当触发事件产生时，
可向信号选择器发送<strong>“选择信号”</strong>。</p>
<ul>
<li>绑定API：<code>xwos_flg_bind()</code></li>
<li>解绑API：<code>xwos_flg_unbind()</code></li>
</ul>
<p>可以参考<a href="#SYNC-SEL">信号选择器</a>的章节获取更多的信息。</p>
<h3 id="_33">示例</h3>
<ul>
<li>应用模块：<code>xwam/example/sync/flg</code></li>
<li>用法：<ul>
<li>在配置文件<code>xwbd/电路板名称/cfg/xwam.h</code>中
    定义宏<code>XWAMCFG_example_sync_flg</code>为<code>1</code>；</li>
<li>在初始化流程中（例如：<code>xwos_main()</code>）调用<code>example_flg_start()</code>启动模块。</li>
</ul>
</li>
</ul>
<h3 id="_34">配置</h3>
<p><a id="SYNC-FLG-CFG"></a></p>
<h5 id="cfgxwosh_2">cfg/xwos.h</h5>
<ul>
<li>MP内核配置：<ul>
<li>同步<ul>
<li><code>XWMPCFG_SYNC_EVT</code>：是否启用事件，取值：1|0；</li>
<li><code>XWMPCFG_SYNC_EVT_MAXNUM</code>：事件位最大数量；</li>
<li><code>XWMPCFG_SYNC_EVT_MEMSLICE</code>：是否启用事件对象缓存，取值：1|0；</li>
</ul>
</li>
</ul>
</li>
<li>UP内核配置：<ul>
<li>同步<ul>
<li><code>XWUPCFG_SYNC_EVT</code>：是否启用事件，取值：1|0；</li>
<li><code>XWUPCFG_SYNC_EVT_MAXNUM</code>：事件位最大数量；</li>
</ul>
</li>
</ul>
</li>
</ul>
<h3 id="api_2">API参考</h3>
<ul>
<li>头文件：<code>xwos/osal/sync/flg.h</code></li>
<li>注释：见头文件</li>
</ul>
<hr />
<h2 id="_35">线程栅栏</h2>
<h3 id="_36">描述</h3>
<p>线程栅栏是用于协调多个线程并行工作的同步机制。线程栅栏允许每个线程等待，
直到所有的合作线程都达到栅栏点，然后从该点继续执行。</p>
<p>玄武OS的线程栅栏：</p>
<ul>
<li>线程栅栏支持的最大线程数量在运行时是固定不变的，但可在编译时进行配置：<ul>
<li>多核系统：<code>XWMPCFG_SYNC_EVT_MAXNUM</code></li>
<li>单核系统：<code>XWUPCFG_SYNC_EVT_MAXNUM</code></li>
</ul>
</li>
</ul>
<h3 id="_37">用法</h3>
<h4 id="_38">线程栅栏的创建、初始化与删除、销毁</h4>
<p>线程栅栏支持静态初始化与销毁，动态创建与删除两种方式：</p>
<ul>
<li>
<p>静态初始化与销毁</p>
<ul>
<li><strong>静态</strong>是指用户预先定义对象，这些对象在编译时由编译器分配内存。</li>
<li>初始化：<code>xwos_br_init()</code></li>
<li>销毁：<code>xwos_br_destroy()</code></li>
</ul>
</li>
<li>
<p>动态创建与删除</p>
<ul>
<li><strong>动态</strong>是指程序在运行时，通过内存分配函数从某个内存区域上申请分配一块内存，
    并把这块内存初始化为所需要的对象。使用完毕后，需要释放内存。</li>
<li>创建：<code>xwos_br_create()</code></li>
<li>删除：<code>xwos_br_delete()</code></li>
</ul>
</li>
</ul>
<h3 id="_39">示例</h3>
<ul>
<li>应用模块：<code>xwam/example/sync/br</code></li>
<li>用法：<ul>
<li>在配置文件<code>xwbd/电路板名称/cfg/xwam.h</code>中
    定义宏<code>XWAMCFG_example_sync_br</code>为<code>1</code>；</li>
<li>在初始化流程中（例如：<code>xwos_main()</code>）调用<code>example_br_start()</code>启动模块。</li>
</ul>
</li>
</ul>
<h3 id="_40">配置</h3>
<p>线程栅栏同事件标志一样，在底层基于玄武OS内核的事件对象实现，配置可参考
<a href="#SYNC-FLG-CFG">同步-事件标志-配置</a></p>
<h3 id="api_3">API参考</h3>
<ul>
<li>头文件：<code>xwos/osal/sync/br.h</code></li>
<li>注释：见头文件</li>
</ul>
<hr />
<h2 id="_41">信号选择器</h2>
<p><a id="SYNC-SEL"></a></p>
<h3 id="_42">描述</h3>
<p>类似于事件标志，信号选择器中包含一幅位图，只不过位图中每个位关联的不再是事件，
而是<strong>同步对象</strong>。每种<strong>同步对象</strong>都可绑定到信号选择器并发送<strong>选择信号</strong>，
使得信号选择器中的对应位被置1，同时使得等待信号选择器的线程被唤醒。</p>
<p>信号选择器用于让单一线程同时处理多个同步对象，类似于POSIX中的<code>select()</code>。</p>
<p><strong>发送信号</strong>对于不同的<strong>同步对象</strong>有不同解释：</p>
<ul>
<li>信号量：指发布操作（V操作），API <code>xwos_sem_post()</code>；</li>
<li>条件量：指广播操作，API <code>xwos_cond_broadcast()</code>，注意，
    单播<code>xwos_cond_unicast()</code>不会向信号选择器发送<strong>选择信号</strong>；</li>
<li>事件标志：指事件标志位图中任何一位发生改变，对应于API：<ul>
<li><code>xwos_flg_s1m()</code></li>
<li><code>xwos_flg_s1i()</code></li>
<li><code>xwos_flg_c0m()</code></li>
<li><code>xwos_flg_c0i()</code></li>
<li><code>xwos_flg_x1m()</code></li>
<li><code>xwos_flg_x1i()</code></li>
</ul>
</li>
<li>线程栅栏：指所有线程抵达栅栏处；</li>
<li>信号选择器：指任何绑定在信号选择器中的<strong>同步对象</strong>向信号选择器发送了<strong>选择信号</strong> 。</li>
</ul>
<p>信号选择器之间可以依次绑定，形成传递链，将<strong>选择信号</strong>在传递链上传递。但要注意，
信号选择器不可相互绑定形成循环链，否则会造成无限传递。</p>
<p><img alt="img" src="../res/figure/xwos-sel.png" title="信号选择器示意图" /></p>
<h3 id="_43">用法</h3>
<h4 id="_44">信号选择器的创建、初始化与删除、销毁</h4>
<p>信号选择器支持静态初始化与销毁，动态创建与删除两种方式：</p>
<ul>
<li>
<p>静态初始化与销毁</p>
<ul>
<li><strong>静态</strong>是指用户预先定义对象，这些对象在编译时由编译器分配内存。</li>
<li>初始化：<code>xwos_sel_init()</code></li>
<li>销毁：<code>xwos_sel_destroy()</code></li>
</ul>
</li>
<li>
<p>动态创建与删除</p>
<ul>
<li><strong>动态</strong>是指程序在运行时，通过内存分配函数从某个内存区域上申请分配一块内存，
    并把这块内存初始化为所需要的对象。使用完毕后，需要释放内存。</li>
<li>创建：<code>xwos_sel_create()</code></li>
<li>删除：<code>xwos_sel_delete()</code></li>
</ul>
</li>
</ul>
<h4 id="_45">绑定与解绑</h4>
<p>玄武OS中所有<strong>同步对象</strong>都带有两个相似的API:</p>
<pre><code class="C">/* 绑定 */
xwer_t xwos_XXX_bind();

/* 解绑 */
xwer_t xwos_XXX_unbind();
</code></pre>

<p><strong>同步对象</strong>绑定操作又分为独占绑定与非独占绑定：</p>
<ul>
<li>独占绑定：是指<strong>同步对象</strong>一旦绑定了信号选择器中的某一位后，其他<strong>同步对象</strong>
    不可再绑定此位；</li>
<li>非独占绑定：是指<strong>同步对象</strong>一旦绑定了信号选择器中的某一位后，其他<strong>同步对象</strong>
    还可继续再绑定此位。</li>
</ul>
<p><strong>同步对象</strong>采用的绑定方式：</p>
<ul>
<li>信号量：独占绑定</li>
<li>条件量：非独占绑定</li>
<li>事件标志：非独占绑定</li>
<li>线程栅栏：非独占绑定</li>
<li>信号选择器：非独占绑定</li>
</ul>
<h3 id="_46">示例</h3>
<ul>
<li>应用模块：<code>xwam/example/sync/sel</code></li>
<li>用法：<ul>
<li>在配置文件<code>xwbd/电路板名称/cfg/xwam.h</code>中
    定义宏<code>XWAMCFG_example_sync_sel</code>为<code>1</code>；</li>
<li>在初始化流程中（例如：<code>xwos_main()</code>）调用<code>example_sel_start()</code>启动模块。</li>
</ul>
</li>
</ul>
<h3 id="_47">配置</h3>
<p>信号量选择器同事件标志一样，在底层基于玄武OS内核的事件对象实现，配置可参考
<a href="#SYNC-FLG-CFG">同步-事件标志-配置</a>。</p>
<h3 id="api_4">API参考</h3>
<ul>
<li>头文件：<code>xwos/osal/sync/sel.h</code></li>
<li>注释：见头文件</li>
</ul>
<h1 id="_48">附录</h1>
<ul>
<li><a href="../00-Index/">返回目录</a></li>
</ul></div>
            </div>
        </div>

        <footer class="col-md-12">
            <hr>
            <p>Documentation built with <a href="https://www.mkdocs.org/">MkDocs</a>.</p>
        </footer>
        <script>
            var base_url = "../..",
                shortcuts = {"help": 191, "next": 78, "previous": 80, "search": 83};
        </script>
        <script src="../../js/base.js" defer></script>
        <script src="../../search/main.js" defer></script>

        <div class="modal" id="mkdocs_search_modal" tabindex="-1" role="dialog" aria-labelledby="searchModalLabel" aria-hidden="true">
    <div class="modal-dialog modal-lg">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title" id="searchModalLabel">搜索</h4>
                <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
            </div>
            <div class="modal-body">
                <p>
                    在这里所有文档：
                </p>
                <form>
                    <div class="form-group">
                        <input type="search" class="form-control" placeholder="搜索..." id="mkdocs-search-query" title="Type search term here">
                    </div>
                </form>
                <div id="mkdocs-search-results"></div>
            </div>
            <div class="modal-footer">
            </div>
        </div>
    </div>
</div><div class="modal" id="mkdocs_keyboard_modal" tabindex="-1" role="dialog" aria-labelledby="keyboardModalLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h4 class="modal-title" id="keyboardModalLabel">Keyboard Shortcuts</h4>
                <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span></button>
            </div>
            <div class="modal-body">
              <table class="table">
                <thead>
                  <tr>
                    <th style="width: 20%;">Keys</th>
                    <th>Action</th>
                  </tr>
                </thead>
                <tbody>
                  <tr>
                    <td class="help shortcut"><kbd>?</kbd></td>
                    <td>Open this help</td>
                  </tr>
                  <tr>
                    <td class="next shortcut"><kbd>n</kbd></td>
                    <td>Next page</td>
                  </tr>
                  <tr>
                    <td class="prev shortcut"><kbd>p</kbd></td>
                    <td>Previous page</td>
                  </tr>
                  <tr>
                    <td class="search shortcut"><kbd>s</kbd></td>
                    <td>Search</td>
                  </tr>
                </tbody>
              </table>
            </div>
            <div class="modal-footer">
            </div>
        </div>
    </div>
</div>

    </body>
</html>
